package com.skivingcloud.security.conf;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.skivingcloud.common.utils.ReturnT;
import com.skivingcloud.validation.exceptions.ValidateCaptchaException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.AuthorizationServiceException;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.csrf.CsrfException;
import org.springframework.security.web.csrf.InvalidCsrfTokenException;
import org.springframework.security.web.csrf.MissingCsrfTokenException;
import org.springframework.security.web.session.SessionInformationExpiredEvent;
import org.springframework.security.web.session.SessionInformationExpiredStrategy;
import org.springframework.stereotype.Component;

import java.io.IOException;

/**
 * @author hushouquan
 */
@Component
public class SecurityAuthenticationHandler implements SessionInformationExpiredStrategy, AccessDeniedHandler, AuthenticationEntryPoint{
    private static final Logger log = LoggerFactory.getLogger(SecurityAuthenticationHandler.class);
    public static final String APPLICATION_JSON_CHARSET_UTF_8 = "application/json;charset=UTF-8";
    public static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
    
    /**
     * 权限不足时的处理
     * @param request 请求参数
     * @param response 返回
     * @param accessDeniedException 认证异常
     * @throws IOException io异常
     */
    @Override
    public void handle(jakarta.servlet.http.HttpServletRequest request, jakarta.servlet.http.HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException {
        String detailMessage;
        if (accessDeniedException instanceof MissingCsrfTokenException) {
            detailMessage = "缺少CSRF TOKEN,请从表单或HEADER传入";
        } else if (accessDeniedException instanceof InvalidCsrfTokenException) {
            detailMessage = "无效的CSRF TOKEN";
        } else if (accessDeniedException instanceof CsrfException) {
            detailMessage = accessDeniedException.getLocalizedMessage();
        } else if (accessDeniedException instanceof AuthorizationServiceException) {
            detailMessage = AuthorizationServiceException.class.getSimpleName() + " " + accessDeniedException.getLocalizedMessage();
        } else {
            detailMessage = "对不起，您没有此操作权限";
        }
        response.setContentType(APPLICATION_JSON_CHARSET_UTF_8);
        response.setStatus(HttpStatus.OK.value());
        response.getWriter().println(OBJECT_MAPPER.writeValueAsString(ReturnT.error(HttpStatus.FORBIDDEN.value(), detailMessage)));
    }
    
    /**
     * 同用户在其他地方登录
     * @param event event
     * @throws IOException 异常
     */
    @Override
    public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException {
        String message = "该会话过期或账号已从其他设备登陆,如果不是您自己的操作请及时修改密码";
        final HttpServletResponse response = event.getResponse();
        response.setContentType(APPLICATION_JSON_CHARSET_UTF_8);
        response.setStatus(HttpStatus.OK.value());
        response.getWriter().println(OBJECT_MAPPER.writeValueAsString(ReturnT.error(HttpStatus.UNAUTHORIZED.value(), message)));
    }
    
    /**
     * 认证失败
     * @param request 请求参数
     * @param response 返回
     * @param authException 认证异常
     * @throws IOException io异常
     */
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
        String detailMessage = authException.getClass().getSimpleName() + " " + authException.getLocalizedMessage();
        if(authException instanceof InsufficientAuthenticationException){
            detailMessage = "请登陆后再访问";
        }
        if(authException instanceof ValidateCaptchaException){
            detailMessage = authException.getMessage();
        }
        response.setContentType(APPLICATION_JSON_CHARSET_UTF_8);
        response.setStatus(HttpStatus.OK.value());
        response.getWriter().println(OBJECT_MAPPER.writeValueAsString(ReturnT.error(HttpStatus.UNAUTHORIZED.value(), detailMessage)));
        log.error(detailMessage, authException);
    }
}
